#include <stdio.h>
#include <stdlib.h>

#include <GL/glew.h>
#ifdef __APPLE__
#include <GLUT/glut.h>
#include <OpenGL/gl.h>
#else
#include <GL/glut.h>
#endif

#include <math.h>
#include <string.h>
#include "vec3f.h"

#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif

#define VNORM_LOC 1
#define TCOORD_LOC 2
#define ECOORD_LOC 3

static const unsigned int MAX_TEX = 3;
static const unsigned int MAX_SHADER = 3;
static const unsigned int VERTEX =  0;
static const unsigned int FRAGMENT = 1;
static unsigned int TEXE =    1;
static unsigned int TEX1 =    0;
static unsigned int TEX2 =    2;

static Vec3f vertices[1210];
static int faces[2260][3];
static Vec3f vnorm[1210];
static Vec3f ccoord[1210];
static float ymax=0.f;
static float radius=2.24;
static float offset_s=-0.03;
static float offset_t=-0.2;
static int v = 0;
static int f = 0;


class Texture{
public: 
    GLuint texName;
    unsigned char * texData;
    GLuint sample_location;
    GLuint coord_location;
    Texture(int type){
        texName=type;
        texData=NULL;
        sample_location=coord_location=-1;
    };
    ~Texture(){
        //delete texData;
        glDeleteTextures( 1, &texName); 
        
    };
};

class Shader{
public: 
    GLuint shaderName;
    const GLchar ** shaderData;
    int shaderType;
    GLuint coord_location;
    Shader(int type){
        shaderType=type;
        shaderData=NULL;
    };
    ~Shader(){
        //delete shaderData;
        glDeleteShader(shaderName);        
    };
};

static Texture * texList[3];
static Shader * shaderList[2];

static void load_obj(char * fn)
{
	FILE * fp; 
        fp = fopen(fn, "rb");

	
	v = 0;
	f = 0;
	char temp[100];

	char* trio[3];

	while(fgets(temp, 100, fp)){
		trio[0] = strtok(temp," ");
		
		if(temp[0] == 'v'){
			trio[0] = strtok(NULL," ");
			trio[1] = strtok(NULL," ");
			trio[2] = strtok(NULL," ");
                        vertices[v]=Vec3f(atof(trio[0]),atof(trio[1]),atof(trio[2]));
			
			if(vertices[v][1]>ymax) ymax = vertices[v][1];
                        vnorm[v]=Vec3f();
                        ccoord[v]=Vec3f();

			v++;
			
        	}
		if(temp[0] == 'f'){
			trio[0] = strtok(NULL," ");
			trio[1] = strtok(NULL," ");
			trio[2] = strtok(NULL," ");
  	  
			faces[f][0] = atoi(trio[0]);
			faces[f][1] = atoi(trio[1]);
			faces[f][2] = atoi(trio[2]);
			f++;
                }
    }
	fclose(fp);  
}



static void calcNorm(){
    	for(int i = 0; i < f; i++){
                    int n1=faces[i][0]-1;
                    int n2=faces[i][1]-1;
                    int n3=faces[i][2]-1;
                // calculate two vectors from a face
                Vec3f v1=vertices[n1]-vertices[n2];
                Vec3f v2=vertices[n3]-vertices[n2];
                
                // calculate surface normal cross product of v1 and v2	
                Vec3f surface_norm=v1.cross(v2);		
                surface_norm.normalize();
                
                // add surface normal the first vertex in the triangle
		vnorm[n1]+=surface_norm;
		vnorm[n2]+=surface_norm;                
		vnorm[n3]+=surface_norm;                

	}
	for(int i = 0; i < v; i++){
		float theta = atan2(vertices[i][2],vertices[i][0]);
		//ccoord[i][0] = radius*cos(theta);
                ccoord[i][0] = (theta+M_PI)/(2*M_PI);
		ccoord[i][1] = vertices[i][1]/ymax;
                vnorm[i].normalize();
	}
}

static void draw(){
        float c=ymax/2;
        float r=.8;
    	glBegin(GL_TRIANGLES);
		for(int i = 0; i < f; i++){
                    int n1=faces[i][0]-1;
                    int n2=faces[i][1]-1;
                    int n3=faces[i][2]-1;
                    Vec3f v1=vertices[n1]*r;
                    Vec3f v2=vertices[n2]*r;
                    Vec3f v3=vertices[n3]*r;

                    Vec3f vn1=-vnorm[n1];
                    Vec3f vn2=-vnorm[n2];
                    Vec3f vn3=-vnorm[n3];

                    glVertexAttrib2f(texList[TEX1]->sample_location,(ccoord[n1][0]+offset_s)*radius,(ccoord[n1][1]+offset_t)*radius);
                    glMultiTexCoord2f(GL_TEXTURE0, ccoord[n1][0],ccoord[n1][1]);
                    glMultiTexCoord2f(GL_TEXTURE1, (ccoord[n1][0]+offset_s)*radius,(ccoord[n1][1]+offset_t)*radius);
                    glNormal3f(vn1[0],vn1[1],vn1[2]);
                    glVertex3f(v1[0],v1[1]-c,v1[2]);

                    glVertexAttrib2f(texList[TEX1]->sample_location,(ccoord[n2][0]+offset_s)*radius,(ccoord[n2][1]+offset_t)*radius);
                    glMultiTexCoord2f(GL_TEXTURE0, ccoord[n2][0],ccoord[n2][1]);
                    glMultiTexCoord2f(GL_TEXTURE1, (ccoord[n2][0]+offset_s)*radius,(ccoord[n2][1]+offset_t)*radius);
                    glNormal3f(vn2[0],vn2[1],vn2[2]);
                    glVertex3f(v2[0],v2[1]-c,v2[2]);

                    glVertexAttrib2f(texList[TEX1]->sample_location,(ccoord[n3][0]+offset_s)*radius,(ccoord[n3][1]+offset_t)*radius);
                    glMultiTexCoord2f(GL_TEXTURE0, ccoord[n3][0],ccoord[n3][1]);
                    glMultiTexCoord2f(GL_TEXTURE1, (ccoord[n3][0]+offset_s)*radius,(ccoord[n3][1]+offset_t)*radius);
                    glNormal3f(vn3[0],vn3[1],vn3[2]);
                    glVertex3f(v3[0],v3[1]-c,v3[2]);

		}
	glEnd();
}

static unsigned char* readPPM(char* filename, int* width, int* height)
{
    FILE* fp;
    int i, w, h, d;
    unsigned char* image;
    char head[70];          /* max line <= 70 in PPM (per spec). */
    
    fp = fopen(filename, "rb");
    if (!fp) {
        perror(filename);
        return NULL;
    }
    
    /* grab first two chars of the file and make sure that it has the
       correct magic cookie for a raw PPM file. */
    fgets(head, 70, fp);
    if (strncmp(head, "P6", 2)) {
        fprintf(stderr, "%s: Not a raw PPM file\n", filename);
        return NULL;
    }
    
    /* grab the three elements in the header (width, height, maxval). */
    i = 0;
    while(i < 3) {
        fgets(head, 70, fp);
        if (head[0] == '#')     /* skip comments. */
            continue;
        if (i == 0)
            i += sscanf(head, "%d %d %d", &w, &h, &d);
        else if (i == 1)
            i += sscanf(head, "%d %d", &h, &d);
        else if (i == 2)
            i += sscanf(head, "%d", &d);
    }
    
    /* grab all the image data in one fell swoop. */
    image = (unsigned char*)malloc(sizeof(unsigned char)*w*h*3);
    fread(image, sizeof(unsigned char), w*h*3, fp);
    fclose(fp);
    
    *width = w;
    *height = h;
    return image;
}
